package fr.cephb.joperon.core.iterator;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import fr.cephb.util.CloseableIterator;

/**
 * An abstract iterator implementing {@link fr.cephb.util.CloseableIterator}
 * This kind of Iterator should always be closed
 * <pre>
 * AbstractIterator iter=null;
 * try
 * 	 {
 *   iter= fun();
 *   (...)//use iterator
 *   }
 *  catch(Exception err)
 *   {
 *   (...)//handle error
 *   }
 *  finally
 *   {
 *   if(iter!=null) iter.close();
 *   }
 * </pre>
 * @author lindenb
 *
 * @param <E> the data returned by this iterator
 */
public  abstract class AbstractIterator<E>
implements CloseableIterator<E> 
	{
	protected boolean _hasNextTested=false;
	protected boolean _hasNext=false;
	protected boolean eofMet=false;
	protected E _nextValue=null;
	
	protected AbstractIterator()
		{
		}
	
	/**
	 * close this iterator
	 */
	@Override
	public void close()
		{
		this.eofMet=true;
		this._hasNextTested=true;
		this._hasNext=false;
		}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException("Cannot clone "+getClass());
		}
	
	/** close this iterator on finalize
	 * but the developper should do this programmaticaly
	 */
	@Override
	protected void finalize() throws Throwable {
		close();
		super.finalize();
		}
	
	/** not implemented will throw a UnsupportedOperationException */
	@Override
	public void remove() {
		throw new UnsupportedOperationException("Cannot remove from "+getClass());
		}
	
	/** return the  number of items and closes the iterator
	 * @return the  number of items */
	public int count()
		{
		int n=0;
		while(hasNext()) { next();++n;}
		close();
		return n;
		}
	
	/** return the items as a Set and closes the iterator
	 * @return the items as a Set */
	public Set<E> asSet()
		{
		HashSet<E> set= new HashSet<E>();
		while(hasNext()) { set.add(next());}
		close();
		return set;
		}
	
	/** return the items as a List and closes the iterator
	 * @return the items as a List */
	public List<E> asList()
		{
		ArrayList<E> L= new ArrayList<E>();
		while(hasNext()) { L.add(next());}
		close();
		return L;
		}
	
	/** 
	 *  return the next item or null if there is none
	 *  but does NOT close the iterator */
	public E nextOrNull()
		{
		return hasNext()?next():null;
		}
	
	@Override
	public E next() {
		if(this._hasNextTested==false)
			{
			hasNext();
			}
		if(!this._hasNext) throw new NoSuchElementException("No next() in "+getClass());
		this._hasNextTested=false;
		this._hasNext=false;
		return this._nextValue;
		}
	
	/** return an iterator iterating from on index for a given number of items
	 * 
	 * @param index start index
	 * @param length number of items to iterate
	 * @return a new iterator
	 */
	public FromToIterator<E> from(int index,int length)
		{
		return new FromToIterator<E>(this,index,length);
		}
	
	/** 
	 * return an iterator iterating from on index 
	 * 
	 * @param index start index
	 * @return a new iterator
	 */
	public FromToIterator<E> from(int index)
		{
		return from(index,Integer.MAX_VALUE);
		}
	}
